package com.brayan.webapp.service.realestate;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.log4j.Logger;
import org.joda.time.LocalDate;

import com.brayan.webapp.model.realestate.Costs;
import com.brayan.webapp.model.realestate.Reservation;
import com.brayan.webapp.model.realestate.ReservationState;
import com.brayan.webapp.repository.realestate.ReservationRepository;
import com.brayan.webapp.service.auxilliary.MailBean;

@Named
@Stateless
public class ReservationBean {

	@Inject
	ReservationRepository reservationRepo;
	@Inject
	PriceModelBean priceModel;
	@Inject
	MailBean mailBean;
	@Inject
	ReservationRepository resRepo;

	private static Logger LOGGER = Logger.getLogger(ReservationBean.class);

	final String ADMIN_EMAIL = "palma@brayan.com";

	public Costs calculateCosts(int numberOfGuests, Date startDate, Date endDate) {
		return calculateCosts(numberOfGuests, LocalDate.fromDateFields(startDate), LocalDate.fromDateFields(endDate));
	}

	public Costs calculateCosts(int numberOfGuests, LocalDate startDate, LocalDate endDate) {

		int numOfGuests = priceModel.getNumberOfGuests(numberOfGuests);
		int numOfDays = priceModel.getDurationInDays(startDate, endDate);
		double reservationCosts = priceModel.calculateReservationCosts(numberOfGuests, startDate, endDate);
		double cleaningFee = priceModel.calculateCleaningFee(numOfDays, numOfGuests);

		Costs costs = new Costs();
		costs.setStartDate(startDate);
		costs.setEndDate(endDate);
		costs.setNumberOfGuests(numOfGuests);
		costs.setCurrency(priceModel.getCurrency());
		costs.setReservationCosts(reservationCosts);
		costs.setCleaningFee(cleaningFee);
		costs.setVatPercentage(priceModel.getVAT());
		costs.setVatAmount(priceModel.getVatAmount(reservationCosts, cleaningFee));
		// This includes VAT.
		costs.setTotalCosts(priceModel.calculateTotalCosts(reservationCosts, cleaningFee));
		costs.setSeasonFactor(priceModel.calculateAverageSeasonFactor(startDate, endDate));
		return costs;
	}

	public void saveReservation(Reservation reservation, String ipAddress) {

		// Set the correct hours to the dates
		reservation.setStartDate(reservation.getStartDate());
		reservation.setEndDate(reservation.getEndDate());

		LOGGER.debug("Attempting to save a new reservation for tenant " + reservation.getTenant().getSurname()
				+ " and period " + reservation.getStartDate() + " to " + reservation.getEndDate());
		reservation.setCosts(calculateCosts(reservation.getNumberOfGuests(),
				LocalDate.fromDateFields(reservation.getStartDate()),
				LocalDate.fromDateFields(reservation.getEndDate())));

		Reservation detachedRes = reservationRepo.saveReservation(reservation);

		// Add geo info async
		reservationRepo.addGeoInfoToReservation(detachedRes, ipAddress);

		// ///PROCESS EMAILS//////

		final int RESPONSE_TIME = 72;
		SimpleDateFormat formater = new SimpleDateFormat("E d. MMMM yyyy", Locale.GERMAN);

		// Send Mail to Admin
		String fullName = reservation.getTenant().getGivenname() + " " + reservation.getTenant().getSurname();
		StringBuilder sbAdminMsg = new StringBuilder(fullName);
		sbAdminMsg.append(" requested a reservation.\n\n");
		sbAdminMsg.append(" Total costs are ");
		sbAdminMsg.append(reservation.getCosts().getTotalCosts());
		sbAdminMsg.append("€.\nCleaning fees are ");
		sbAdminMsg.append(reservation.getCosts().getCleaningFee());
		sbAdminMsg.append("€.\nStarting from " + formater.format(reservation.getStartDate()));
		sbAdminMsg.append(" to ");
		sbAdminMsg.append(formater.format(reservation.getEndDate()));
		sbAdminMsg.append(".\n\nPlease confirm or reject the inquiry online within ");
		sbAdminMsg.append(RESPONSE_TIME);
		sbAdminMsg.append(" on http://www.brayan.com");

		mailBean.send(ADMIN_EMAIL, "Palma - Reservationsanfrage " + fullName, sbAdminMsg.toString());

		// Send Mail to customer
		StringBuilder sbTenantMsg = new StringBuilder(
				"Bon día.\n\nDu hast eine Reservations für unsere Wohnung in Palma aufgeben. Wir prüfen das.\n\n");
		sbTenantMsg.append("Beginn vom ");
		sbTenantMsg.append(formater.format(reservation.getStartDate()));
		sbTenantMsg.append(" bis ");
		sbTenantMsg.append(formater.format(reservation.getEndDate()));
		sbTenantMsg.append(". Die Totalkosten belaufen sich auf ");
		sbTenantMsg.append(reservation.getCosts().getTotalCosts());
		sbTenantMsg.append("€.\n\nDavon sind ");
		sbTenantMsg.append(reservation.getCosts().getCleaningFee());
		sbTenantMsg.append("€ Raumpflegekosten.\n\nWir informieren dich innerhalb ");
		sbTenantMsg.append(RESPONSE_TIME);
		sbTenantMsg.append(" Stunden.\n\n\nSaludos de Palma\nMelinda & Brayan");

		mailBean.send(reservation.getTenant().getEmail(), "Palma - deine Reservationsanfrage", sbTenantMsg.toString());
	}

	/**
	 * Sets at what hour the guest must have left.
	 * 
	 * @return
	 */
	// public Date setLeavingHour(Date date) {
	// Calendar cal = Calendar.getInstance();
	// cal.setTime(date);
	// cal.set(Calendar.HOUR_OF_DAY, 9);
	// cal.set(Calendar.MINUTE, 0);
	// cal.set(Calendar.SECOND, 0);
	// cal.set(Calendar.MILLISECOND, 0);
	//
	// return cal.getTime();
	// }

	/**
	 * Sets at what hour the guest may over take the flat.
	 * 
	 * @return
	 */
	// public Date setTakeOverHour(Date date) {
	// Calendar cal = Calendar.getInstance();
	// cal.setTime(date);
	// cal.set(Calendar.HOUR_OF_DAY, 12);
	// cal.set(Calendar.MINUTE, 0);
	// cal.set(Calendar.SECOND, 0);
	// cal.set(Calendar.MILLISECOND, 0);
	//
	// return cal.getTime();
	// }

	public void updateReservation(Reservation reservation) {
		LOGGER.debug("Attempting to update a reservation for tenant " + reservation.getTenant().getSurname()
				+ " and period " + reservation.getStartDate() + " to " + reservation.getEndDate());

		reservationRepo.saveReservation(reservation);

	}

	public void updateReservationState(Reservation reservation, ReservationState state) {

		ReservationState oldState = reservation.getReservationState();
		if (state != oldState) {
			LOGGER.debug("Attempting to update a reservation state for tenant " + reservation.getTenant().getSurname()
					+ " and period " + reservation.getStartDate() + " to " + reservation.getEndDate());
			reservation.setReservationState(state.toString());
			reservationRepo.saveReservation(reservation);
			try {
				mailBean.send(
						reservation.getTenant().getEmail(),
						"Palma - Reservationsanfrage Attika Wohnung - Status Update",
						"Der Status deiner Reservationsanfrage wurde von '" + oldState.toString() + "' auf '"
								+ state.toString() + "' geändert.");
				LOGGER.info("Customer " + reservation.getTenant().getSurname() + " with reservation id "
						+ reservation.getId() + " is updated on the reservation status.");
			} catch (Exception ex) {
				LOGGER.error("Failed to send a reservation state upate to the customer "
						+ reservation.getTenant().getSurname() + " and reservation id " + reservation.getId() + ".", ex);
			}

		}
	}

	public void deleteReservation(Reservation reservation) {
		try {
			mailBean.send(
					reservation.getTenant().getEmail(),
					"Palma - Reservationsanfrage für Attika Wohnung zurückgewiesen",
					"Deine Anfrage wurde zurückgewiesen. Wahrscheinlich gibt es Datumsüberschneidungen, wir haben das so vereinbart oder ähnliches. Bei fragen bitte einfach Anrufen oder auf dieses mail antworten.\n\nSaludos, Melinda & Brayan",
					true);
			LOGGER.info("Customer " + reservation.getTenant().getSurname() + " with reservation id "
					+ reservation.getId() + " is deleted.");
		} catch (Exception ex) {
			LOGGER.error("Failed to send a deletion report to the customer " + reservation.getTenant().getSurname()
					+ " and reservation id " + reservation.getId() + ".", ex);
		}
		reservationRepo.deleteReservation(reservation);

	}
}
